﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace SmartRoute.IO
{
    [Serializable]
    public class BingProject: IDeserializationCallback, Data.IRoutingService
    {
        private List<Data.Location> _locations;

        public IEnumerable<Data.Route> BestRoutes
        {
            get
            {
                return 
                    (Optimization.ISolutionFunctions.SolveForNBuses(_routeCache,_depot, _algorithmState.Champion, _numberOfBuses)
                    .SelectMany(x => x.Select(y => Data.Bus.ConvertToRoute(y))));
            }
        }
        /// <summary>
        /// User can bookmark locations here.
        /// </summary>
        public List<Data.Location> MemorizedLocations
        {
            get { return _locations; }
        }

        private Data.Location _depot;

        private Data.DynamicRouteCache _routeCache;

        private string _key;

        private uint _populationSize;

        public uint PopulationSize
        {
            get { return _populationSize; }
            set { 
                    _populationSize = value;
                    _algorithmState.PopulationSize = value;
                }
        }

        private uint _numberOfBuses;

        public uint NumberOfBuses
        {
            get { return _numberOfBuses; }
            set
            {
                _numberOfBuses = value;
                _algorithmState.NumberOfBuses = value;
            }
        }

        private Analytics.CostFunctionParameters _parameters;

        public Analytics.CostFunctionParameters Parameters
        {
            get { return _parameters; }
            set { 
                    _parameters = value;
                    _algorithmState.Parameters = value;
                }
        }

        private List<Data.School> _schools;

        private Optimization.GeneticAlgorithm<Analytics.CostFunctionParameters> _algorithmState;

        public Optimization.GeneticAlgorithm<Analytics.CostFunctionParameters> AlgorithmState
        {
            get { return _algorithmState; }
            set { _algorithmState = value; }
        }

        private void reinitializeAlgorithm()
        {
            _algorithmState = new SmartRoute.Optimization.GeneticAlgorithm<SmartRoute.Analytics.CostFunctionParameters>
                (_routeCache, Schools,
                new Randomness.RandomSource(DateTime.Now.Millisecond),                
                new Analytics.Analyzer<Analytics.CostFunctionParameters>(Analytics.CostFunctions.SimpleCostFunction, Parameters), _populationSize,
                _mutationRate, _numberOfBuses, _depot);
        }

        public IEnumerable<Data.School> Schools
        {
            get { return _schools; }
        }

        public void addSchool(Data.School toAdd)
        {
            _schools.Add(toAdd);
            reinitializeAlgorithm();
        }

        public void removeSchool(Data.School toRemove)
        {
            if (_schools.Contains(toRemove)) _schools.Remove(toRemove);
            reinitializeAlgorithm();
        }

        private double _mutationRate;

        public double MutationRate
        {
            get { return _mutationRate; }
            set
            {
                _mutationRate = value;
                _algorithmState.MutationRate = value;
            }
        }

        [NonSerialized]
        private Data.IRoutingService _routeService;

        public BingProject(string APIKey, Analytics.CostFunctionParameters algorithmParameters, uint populationSize, 
            uint numBuses, double mutationRate, double busCost, Data.Location depot)
        {
            _key = APIKey;
            _routeService = new BingMaps.RoutingServices(_key);
            _routeCache = new Data.DynamicRouteCache(_routeService);
            _schools = new List<Data.School>();
            _parameters = algorithmParameters;
            _populationSize = populationSize;
            _numberOfBuses = numBuses;
            _depot = depot;
            _locations = new List<Data.Location>();
            reinitializeAlgorithm();
        }

        protected BingProject() { }

        #region IDeserializationCallback Members

        private void reinitializeRouteServices()
        {
            _routeService = new BingMaps.RoutingServices(_key);
            _routeCache.RealRoutingService = _routeService;
            _algorithmState.RouteService = _routeCache;
        }

        public void OnDeserialization(object sender)
        {
            reinitializeRouteServices();
        }

        #endregion

        #region IRoutingService Members

        public SmartRoute.Data.Route FromTo(SmartRoute.Data.Location source, SmartRoute.Data.Location destination)
        {
            return _routeCache.FromTo(source, destination);
        }

        #endregion

        public void save()
        {
            using(var file = System.IO.File.OpenWrite("current.smrtprj"))
            {
                var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                bf.Serialize(file, this);
            }
        }

        public static BingProject Reload()
        {
            using(var file = System.IO.File.OpenRead("current.smrtprj"))
            {
                var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                return (BingProject)bf.Deserialize(file);
            }
        }
    }
}
